package com.gitee.wsl.mathematics.geometry.api

import com.gitee.wsl.io.dataproxy.DataProxyContainer
import com.gitee.wsl.mathematics.coordinate.Coordinate
import com.gitee.wsl.mathematics.coordinate.MutableCoordinate
import com.gitee.wsl.mathematics.number.NumberCalcContainer

interface PointContainer<N:Number,V: Coordinate<N, V>>: DataProxyContainer<V>, NumberCalcContainer<N> {
    /*fun getPolylineLength( ): Double {
        return proxy.reduce { acc, a,b -> acc += a.tangentDistance(b)  }
        var out = 0.0
        var prev = Point.ZERO
        for (n in 0 until proxy.size) {
            val p = get(n)
            if (n > 0) out += Point.distance(prev, p)
            prev = p
        }
        return out
    }*/

    /** Get the element from the set nearest to `pt` or `null`
     * if the set is empty.
     * @param pt reference point
     * @return the element from the set nearest to `pt` or `null`
     * if the set is empty
     */
    fun nearestVertex(pt: V): V?

    /** Get the element from the set farthest to `pt` or `null`
     * if the set is empty.
     * @param pt reference point
     * @return the element from the set farthest to `pt` or `null`
     * if the set is empty
     */
    fun farthestVertex(pt: V): V?

    /** Get a collection containing the set elements in order of increasing
     * distance from `pt`.
     * @param pt reference point
     * @return collection containing the set elements in order of increasing
     * distance from `pt`
     */
    fun nearToFarVertexes(pt: V): Collection<V>

    /** Get a collection containing the set elements in order of decreasing
     * distance from `pt`.
     * @param pt reference point
     * @return collection containing the set elements in order of decreasing
     * distance from `pt`
     */
    fun farToNearVertexes(pt: V): Collection<V>

    fun abs()   = proxy.update {  t -> t.abs }
    fun sign()  = proxy.update {  t -> t.sign }
    fun ceil()  = proxy.update {  t -> t.ceil }
    fun floor() = proxy.update {  t -> t.floor }
    fun round() = proxy.update {  t -> t.round }

    fun scale(factor: N) = proxy.update {  t -> t * factor }

    operator fun timesAssign(v: Number) = proxy.update {  t -> t * v }

    operator fun divAssign(v: Number) = proxy.update {  t -> t / v }
}

interface MutablePointContainer<N:Number,V: MutableCoordinate<N, V>>:PointContainer<N,V>{
    /*fun abs()   = proxy.update {  t -> t.abs() }
    fun sign()  = proxy.update {  t -> sign(t) }
    fun ceil()  = proxy.update {  t -> ceil(t) }
    fun floor() = proxy.update {  t -> floor(t) }
    fun round() = proxy.update {  t -> round(t) }

    fun scale(factor: N) = proxy.update {  t -> t * factor }

    operator fun timesAssign(v: Number) = proxy.update {  t -> t * v }

    operator fun divAssign(v: Number) = proxy.update {  t -> t / v }*/
}